﻿using System;
using System.Linq;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.OLE.Interop;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Shell;
using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
using Process = System.Diagnostics.Process;
using System.CodeDom.Compiler;
using VSLangProj80;
using Microsoft.VisualStudio.Designer.Interfaces;
using System.Text;
using System.Diagnostics;
using System.Collections.Generic;
using EnvDTE;
using Microsoft.VisualStudio.SharePoint;
using System.IO;
using System.Windows.Forms;
using CodeCounsel.SharePoint.DevTools.ItemTypes;

namespace CodeCounsel.SharePoint.DevTools
{
    [CodeGeneratorRegistration(typeof(SPMetalGenerator),
         "SPMetalGenerator", vsContextGuids.vsContextGuidVCSProject)]
    [ProvideObject(typeof(SPMetalGenerator))]
    [Guid(VSPackageGuids.SPMetalGeneratorText)]
    public class SPMetalGenerator
         : SitedObject, IVsSingleFileGenerator
    {
        int IVsSingleFileGenerator.DefaultExtension(out string defaultExtension)
        {
            defaultExtension = null;
            CodeDomProvider provider = GetCodeDomProvider();
            defaultExtension = ".Designer." + provider.FileExtension;
            return VSConstants.S_OK;
        }

        int IVsSingleFileGenerator.Generate(string inputFilePath, string inputFileContents,
            string defaultNamespace, IntPtr[] outputFileContents,
            out uint output, IVsGeneratorProgress generateProgress)
        {
            Cursor current = Cursor.Current;
            try
            {
                Cursor.Current = Cursors.WaitCursor;
                
                ProjectItem projectItem = (ProjectItem)ServiceProvider.GetService(typeof(ProjectItem)); ;
                Project project = projectItem.ContainingProject;

                ISharePointProjectService sharePointService = ProjectUtilities.GetSharePointService();

                CodeDomProvider codeDomProvider = GetCodeDomProvider();
                string language = String.Equals(codeDomProvider.FileExtension, "cs", StringComparison.InvariantCultureIgnoreCase) ?
                    "CSharp" : "VB";
                ISharePointProject sharePointProject = sharePointService.Convert<Project, ISharePointProject>(project); 
                string spmetalPath = Path.Combine(sharePointService.SharePointInstallPath, @"bin\spmetal.exe");
                string tempFile = Path.GetTempFileName();
                Dictionary<string, string> arguments = new Dictionary<string, string>();
                arguments.Add("web", sharePointProject.SiteUrl.ToString());
                arguments.Add("namespace", defaultNamespace);
                arguments.Add("language", language);
                arguments.Add("parameters", inputFilePath);
                arguments.Add("code", tempFile);
                ProcessStartInfo startInfo = new ProcessStartInfo(spmetalPath);
                startInfo.Arguments = String.Concat(arguments.Select(
                    kvp => String.Format(@" /{0}:""{1}""", kvp.Key, kvp.Value)));
                startInfo.RedirectStandardOutput = true;
                startInfo.UseShellExecute = false;
                startInfo.CreateNoWindow = true;
                
                Process process = Process.Start(startInfo);
                string debug = process.StandardOutput.ReadToEnd();
                process.WaitForExit();
                if (File.Exists(tempFile))
                {
                    try
                    {
                        string outputString = File.ReadAllText(tempFile);
                        byte[] content = Encoding.Default.GetBytes(outputString);
                        int length = content.Length;
                        IntPtr mem = Marshal.AllocCoTaskMem(length);
                        Marshal.Copy(content, 0, mem, length);
                        outputFileContents[0] = mem;
                        output = (uint)length;
                    }
                    finally
                    {
                        File.Delete(tempFile);
                    }
                    return VSConstants.S_OK;
                }
                else
                {
                    output = 0;
                    return VSConstants.E_FAIL;
                }
            }
            finally
            {
                Cursor.Current = current;
            }
        }

        protected CodeDomProvider GetCodeDomProvider()
        {
            IVSMDCodeDomProvider provider = (IVSMDCodeDomProvider)GetService(typeof(SVSMDCodeDomProvider));
            return (CodeDomProvider)provider.CodeDomProvider;
        }
    }
}